package org.dromara.common.tenant.config

import cn.dev33.satoken.dao.SaTokenDao
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor
import org.dromara.common.core.utils.reflect.ReflectUtils
import org.dromara.common.redis.config.RedisConfig
import org.dromara.common.redis.config.properties.RedissonProperties
import org.dromara.common.tenant.core.TenantSaTokenDao
import org.dromara.common.tenant.handle.PlusTenantLineHandler
import org.dromara.common.tenant.handle.TenantKeyPrefixHandler
import org.dromara.common.tenant.manager.TenantSpringCacheManager
import org.dromara.common.tenant.properties.TenantProperties
import org.redisson.config.ClusterServersConfig
import org.redisson.config.Config
import org.redisson.config.SingleServerConfig
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer
import org.springframework.boot.autoconfigure.AutoConfiguration
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.cache.CacheManager
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Primary

/**
 * 租户配置类
 *
 * @author LikeYouDo
 * @date 2025/7/17
 */
@EnableConfigurationProperties(TenantProperties::class)
@AutoConfiguration(after = [RedisConfig::class])
@ConditionalOnProperty(value = ["tenant.enable"], havingValue = "true")
class TenantConfig {

    companion object {
        @ConditionalOnClass(TenantLineInnerInterceptor::class)
        @AutoConfiguration
        class MybatisPlusConfiguration {
            /**
             * 多租户插件
             */
            @Bean
            fun tenantLineInnerInterceptor(tenantProperties: TenantProperties): TenantLineInnerInterceptor {
                return TenantLineInnerInterceptor(PlusTenantLineHandler(tenantProperties))
            }
        }
    }

    @Bean
    fun tenantRedissonCustomizer(redissonProperties: RedissonProperties): RedissonAutoConfigurationCustomizer {
        return RedissonAutoConfigurationCustomizer { config: Config ->
            val nameMapper = TenantKeyPrefixHandler(redissonProperties.keyPrefix)
            val singleServerConfig = ReflectUtils.invokeGetter<SingleServerConfig?>(config, "singleServerConfig")
            if (singleServerConfig != null) {
                // 使用单机模式
                // 设置多租户 redis key前缀
                singleServerConfig.nameMapper = nameMapper
            }
            val clusterServersConfig =
                ReflectUtils.invokeGetter<ClusterServersConfig?>(config, "clusterServersConfig")
            // 集群配置方式 参考下方注释
            if (clusterServersConfig != null) {
                // 设置多租户 redis key前缀
                clusterServersConfig.nameMapper = nameMapper
            }
        }
    }

    /**
     * 多租户缓存管理器
     */
    @Primary
    @Bean
    fun tenantCacheManager(): CacheManager {
        return TenantSpringCacheManager()
    }

    /**
     * 多租户鉴权dao实现
     */
    @Primary
    @Bean
    fun tenantSaTokenDao(): SaTokenDao {
        return TenantSaTokenDao()
    }
}
